from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout,CMakeDeps
from conan.tools.files import copy, get,chdir, collect_libs
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.scm import Git
import os,glob

class SampleRecipe(ConanFile):
    name = "abseil"  # name of the package
    version = "20240722"  # version of the package, assuming a version for illustration
    user = "thirdparty"
    channel = "stable"  # stable development
    license = "Apache-2.0"
    author = "Abseil Team"
    url = "https://github.com/abseil/abseil-cpp"
    description = "Abseil C++ is an open-source collection of library code designed to augment the C++ standard library."
    topics = ("abseil", "c++", "library")
    settings = "os", "arch", "compiler", "build_type"  # Abseil 是 C++ 库，需要指定编译器和构建类型
    options = {"shared": [True, False], "fPIC": [True, False], "usr_mode": ["cmake", "autotools"]}  # options of the package
    default_options = {"shared": True, "fPIC": True, "usr_mode": "cmake"}  # default options of the package
    # exports_sources = "expat/*" 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.build_mode = "cmake"   
        self.work_dir = ""
    def source(self):# two step
 
        # Step 1: Clone the repository
        git = Git(self)
        git.clone("ssh://git@172.16.57.28:2289/ads/thirdparty/abseil-cpp.git", target=self.source_folder)

        # Step 2: Check if the .git folder exists to ensure the repository is cloned correctly
        if not os.path.exists(os.path.join(self.source_folder, ".git")):
            raise ConanException("Git repository was not cloned successfully.")

        # Step 3: Switch to the desired branch (or tag) after cloning
        with chdir(self, self.source_folder):  # Ensure we're in the correct directory
            git.checkout("v20240722.0")

        self.output.info("source ：self.source_folder  = " + self.source_folder)
        # 如果cmakelist.txt在subfolder文件夹下,则需要将文件夹移动到source_folder下
#        self.work_dir = os.path.join(self.source_folder, "subfolder")
    # def requirements(self):
    #     self.requires("fmt/10.2.1")

    def config_options(self):
        if self.settings.os == "Windows":
            del self.options.fPIC # Windows does not require -fPIC flag

    def layout(self):# first step   
        cmake_layout(self)
        self.output.info("layout ： self.folders.source = " + self.folders.source)    
        #self.folders.source = os.path.join(self.folders.source, "expat")

    def generate(self):# third step
        self.detect_build_system()
        self.output.info("generate pwd = " + os.getcwd())
        if self.build_mode == "cmake":
            tc = CMakeToolchain(self)
            tc.variables["ABSL_PROPAGATE_CXX_STD"] = "ON"  # 在这里配置变量  
            tc.variables["ABSL_BUILD_TESTING"] = "OFF"  # 在这里配置变量
            tc.variables["ABSL_BUILD_TEST_HELPERS"] = "OFF"  # 在这里配置变量
            
            tc.generate()
            deps = CMakeDeps(self)
            deps.generate()
        elif self.build_mode == "autotools":
            tc = AutotoolsToolchain(self)
            tc.generate()
        else:
            raise Exception("No build system found. Please provide a CMakeLists.txt or a configure script.")

    def build(self):
        self.output.info(" build pwd = " + os.getcwd())    
        if self.build_mode == "cmake":
            self.output.info("执行 CMake 构建流程")
            cmake = CMake(self)    
            cmake.configure()
            cmake.build()
        elif self.build_mode == "autotools":    
            with chdir(self, self.source_folder):
                autotools = Autotools(self)
                autotools.configure(args=["--prefix={}".format(self.package_folder)])
                autotools.make()
    def package(self):
        self.output.info(" package pwd = " + os.getcwd())    
        if self.build_mode == "cmake":
            cmake = CMake(self)
            cmake.install()
        elif self.build_mode == "autotools":  
            with chdir(self, self.source_folder):
                autotools = Autotools(self)
                autotools.install()
            
    def package_info(self):
        #
        # 1) 让 Conan 生成 abslConfig.cmake / abslTargets.cmake
        #
        self.cpp_info.set_property("cmake_file_name", "absl")  # 下游可以 find_package(absl CONFIG REQUIRED)

        #
        # 2) 扫描已编译出的 libabsl_*.so / .a，自动创建组件(带实际库)
        #
        lib_dir = os.path.join(self.package_folder, "lib")

        absl_lib_files = []
        absl_lib_files += glob.glob(os.path.join(lib_dir, "libabsl_*.so*"))
        absl_lib_files += glob.glob(os.path.join(lib_dir, "libabsl_*.a"))
        absl_lib_files = list(set(absl_lib_files))  # 去重

        # 存一个集合，记录我们"确实有库"的组件名字，供后面聚合
        library_based_components = set()

        for fullpath in absl_lib_files:
            fname = os.path.basename(fullpath)
            # 去掉前缀 "lib"
            if fname.startswith("lib"):
                fname = fname[3:]  # 例: "absl_strings.so.2407.0.0"
            # 切掉可能的后缀 ".so", ".so.2407.0.0", ".a" 等
            comp_base = fname.split('.', 1)[0]  # 例: "absl_strings"
            comp_name = comp_base  # 例: "absl_strings"

            # libs = [comp_base] => Conan 会最终链接 "libabsl_strings.(so/a)"
            self.cpp_info.components[comp_name].libs = [comp_base]

            # 让 target 名称是 absl::<suffix>，例如 absl::strings
            suffix = comp_base.replace("absl_", "")  # 例: "strings"
            cmake_target = f"absl::{suffix}"
            self.cpp_info.components[comp_name].set_property("cmake_target_name", cmake_target)

            # 如果你还想兼容 Conan 1.x 的 find_package 模式：
            self.cpp_info.components[comp_name].names["cmake_find_package"] = suffix
            self.cpp_info.components[comp_name].names["cmake_find_package_multi"] = suffix

            library_based_components.add(comp_name)
        #
        # 3) 对于只存在头文件却无对应库的 absl 子模块，也人工创建 空组件
        #
        # 你可以根据 /include/absl/ 下的目录来列一个清单，
        # 或者自己维护一个列表比如:
        header_only_subdirs = [
            "algorithm", "cleanup", "crc", "flags", "hash", "memory", "numeric", 
            "random", "strings", "time", "utility", "base", "container", "debugging",
            "functional", "log", "meta", "profiling", "status", "synchronization", "types"
        ]
        for subdir in header_only_subdirs:
            # 例: 生成 "absl_algorithm" 作为组件名
            comp_name = f"absl_{subdir}"
            if comp_name not in self.cpp_info.components:
                # 说明上面没扫描到真实库 => 我们创建一个空组件
                self.cpp_info.components[comp_name].libs = []  # 不链接任何库
                # cmake_target 叫 "absl::algorithm" ...
                cmake_target = f"absl::{subdir}"
                self.cpp_info.components[comp_name].set_property("cmake_target_name", cmake_target)

                # 同理，兼容 Conan 1.x
                self.cpp_info.components[comp_name].names["cmake_find_package"] = subdir
                self.cpp_info.components[comp_name].names["cmake_find_package_multi"] = subdir
        #
        # 4) 再注册一个聚合组件 absl::absl，把所有组件都 requires 进来
        #
        self.cpp_info.components["absl_aggregated"].libs = []
        self.cpp_info.components["absl_aggregated"].set_property("cmake_target_name", "absl::absl")

        for comp_key in self.cpp_info.components.keys():
            if comp_key != "absl_aggregated":
                self.cpp_info.components["absl_aggregated"].requires.append(comp_key)
        #
        # 5) 平台层面的依赖(如 pthread)
        #
        if self.settings.os in ["Linux", "FreeBSD"]:
            for comp_obj in self.cpp_info.components.values():
                comp_obj.system_libs.append("pthread")


    def detect_build_system(self):
        cmake_file_path = os.path.join(self.source_folder, "CMakeLists.txt")
        
        if os.path.exists(cmake_file_path):
            self.output.info("CMakeLists.txt exists: Yes")
        elif os.path.exists(os.path.join(self.source_folder, "configure")):
            self.build_mode = "autotools"
            self.output.info("configure exists: Yes")
            # 如果不加权限,configure()方法有可能无法执行
            os.chmod(os.path.join(self.source_folder, "configure"), 0o755)
        else: #目前只处理 CMakeLists.txt 和 configure
            self.output.error("CMakeLists.txt exists: No")
            self.output.error("configure exists: No")
            self.build_mode = str(self.options.usr_mode)
            self.output.info("build_mode = " + self.build_mode)
            # raise Exception("No build system found. Please provide a CMakeLists.txt or a configure script.")    
